#include "Cube.h"

#include <DXUT.h>
#include <stdexcept>

e3d::Cube::Cube(	ID3D10Device* device, ID3D10Effect* effect,
					D3DXVECTOR3 position, D3DXVECTOR3 rotation, D3DXVECTOR3 size )
:	m_device( device ),
	m_effect( effect ),
	m_position( position ), 
	m_rotation( rotation ),
	m_size( size )
{
	m_vertices[0].position = D3DXVECTOR3(1, 0, 1);
	m_vertices[0].normal = D3DXVECTOR3(0.33f, -0.33f, 0.33f );
	m_vertices[0].color = D3DXVECTOR4( 0.33f, -0.33f, 0.33f, 1.0f );

	m_vertices[1].position = D3DXVECTOR3(1, 0, 0);
	m_vertices[1].normal = D3DXVECTOR3(0.33f, -0.33f, -0.33f );
	m_vertices[1].color = D3DXVECTOR4( 0.33f, -0.33f, -0.33f, 1.0f );

	m_vertices[2].position = D3DXVECTOR3(0, 0, 0);
	m_vertices[2].normal = D3DXVECTOR3(-0.33f, -0.33f, -0.33f );
	m_vertices[2].color = D3DXVECTOR4( -0.33f, -0.33f, -0.33f, 1.0f );

	m_vertices[3].position = D3DXVECTOR3(0, 0, 1);
	m_vertices[3].normal = D3DXVECTOR3(-0.33f, -0.33f, 0.33f );
	m_vertices[3].color = D3DXVECTOR4( -0.33f, -0.33f, 0.33f, 1.0f );

	m_vertices[4].position = D3DXVECTOR3(1, 1, 1);
	m_vertices[4].normal = D3DXVECTOR3( 0.33f, 0.33f, 0.33f );
	m_vertices[4].color = D3DXVECTOR4( 0.33f, 0.33f, 0.33f, 1.0f );

	m_vertices[5].position = D3DXVECTOR3(1, 1, 0);
	m_vertices[5].normal = D3DXVECTOR3(0.33f, 0.33f, -0.33f );
	m_vertices[5].color = D3DXVECTOR4( 0.33f, 0.33f, -0.33f, 1.0f );

	m_vertices[6].position = D3DXVECTOR3(0, 1, 0);
	m_vertices[6].normal = D3DXVECTOR3(-0.33f, 0.33f, -0.33f );
	m_vertices[6].color = D3DXVECTOR4( -0.33f, 0.33f, -0.33f, 1.0f );

	m_vertices[7].position = D3DXVECTOR3(0, 1, 1);
	m_vertices[7].normal = D3DXVECTOR3(-0.33f, 0.33f, 0.33f );
	m_vertices[7].color = D3DXVECTOR4( -0.33f, 0.33f, 0.33f, 1.0f );

	unsigned int indexBuffer[23] = {
		6,6,7,2,3,1,0,0,3,3,7,0,4,1,5,5,4,4,7,5,6,1,2
	};

	D3D10_INPUT_ELEMENT_DESC vertLayout[] = 
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0 }, 
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0 } 
	};
	unsigned int numElements = sizeof(vertLayout) / sizeof(vertLayout[0]);

	D3D10_BUFFER_DESC vertexBufferDesc;
	vertexBufferDesc.Usage = D3D10_USAGE_DEFAULT;
	vertexBufferDesc.ByteWidth = sizeof( e3d::ColoredVertex ) * 8;
	vertexBufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	vertexBufferDesc.CPUAccessFlags = 0;
	vertexBufferDesc.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA vertexInitData;
	vertexInitData.pSysMem = m_vertices;
	if( FAILED( m_device->CreateBuffer( &vertexBufferDesc, &vertexInitData, &m_vertexBuffer ) ) )
		throw std::logic_error("Could not create vertex buffer");

	ID3D10EffectTechnique* tech = m_effect->GetTechniqueByName("PhongShading");
	D3D10_PASS_DESC PassDesc;
	tech->GetPassByName( "standard" )->GetDesc( &PassDesc );
	if( FAILED( m_device->CreateInputLayout( vertLayout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &m_vertexLayout)))
		throw std::logic_error("Could not create input layout");

	D3D10_BUFFER_DESC indexBufferDesc;
	indexBufferDesc.Usage = D3D10_USAGE_DEFAULT;
	indexBufferDesc.ByteWidth = sizeof( unsigned int ) * 23;
	indexBufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA indexInitData;
	indexInitData.pSysMem = indexBuffer;
	if( FAILED( m_device->CreateBuffer( &indexBufferDesc, &indexInitData, &m_indexBuffer ) ) )
		throw std::logic_error("Could not create index buffer");
	
}

e3d::Cube::~Cube()
{
	m_device->IASetIndexBuffer( NULL, DXGI_FORMAT_R32_UINT, 0);
	SAFE_RELEASE( m_vertexBuffer );
	SAFE_RELEASE( m_vertexLayout );
	SAFE_RELEASE( m_indexBuffer );
}


void e3d::Cube::render( ID3D10EffectTechnique* tech, const D3DXVECTOR3* camPos )
{
	// Set layout and bind buffer to Input Assembler stage
	unsigned int stride = sizeof( e3d::TexturedVertex );
	unsigned int offset = 0;

	m_device->IASetInputLayout( m_vertexLayout );
	m_device->IASetVertexBuffers( 0, 1, &m_vertexBuffer, &stride, &offset );

	m_device->IASetIndexBuffer( m_indexBuffer, DXGI_FORMAT_R32_UINT, 0 );
	m_device->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

	D3D10_TECHNIQUE_DESC techDesc;
	tech->GetDesc( &techDesc );
	tech->GetPassByName( "standard" )->Apply(0);
	m_device->DrawIndexed( 23, 0, 0 );
}

e3d::BoundingBox e3d::Cube::boundingBox() const
{
	e3d::BoundingBox bb;
	bb.bottomRightBack = D3DXVECTOR3(	m_vertices[0].position.x * m_size.x, 
										m_vertices[0].position.y * m_size.y, 
										m_vertices[0].position.z * m_size.z );

	bb.bottomRightFront = D3DXVECTOR3(	m_vertices[1].position.x * m_size.x, 
										m_vertices[1].position.y * m_size.y, 
										m_vertices[1].position.z * m_size.z );

	bb.bottomLeftFront = D3DXVECTOR3(	m_vertices[2].position.x * m_size.x, 
										m_vertices[2].position.y * m_size.y, 
										m_vertices[2].position.z * m_size.z );

	bb.bottomLeftBack = D3DXVECTOR3(	m_vertices[3].position.x * m_size.x, 
										m_vertices[3].position.y * m_size.y, 
										m_vertices[3].position.z * m_size.z );

	bb.topRightBack = D3DXVECTOR3(	m_vertices[4].position.x * m_size.x, 
									m_vertices[4].position.y * m_size.y, 
									m_vertices[4].position.z * m_size.z );

	bb.topRightFront = D3DXVECTOR3(	m_vertices[5].position.x * m_size.x, 
									m_vertices[5].position.y * m_size.y, 
									m_vertices[5].position.z * m_size.z );

	bb.topLeftFront = D3DXVECTOR3(	m_vertices[6].position.x * m_size.x, 
									m_vertices[6].position.y * m_size.y, 
									m_vertices[6].position.z * m_size.z );

	bb.topLeftBack = D3DXVECTOR3(	m_vertices[7].position.x * m_size.x, 
									m_vertices[7].position.y * m_size.y, 
									m_vertices[7].position.z * m_size.z );
	return bb;
}